/*
 * Copyright (c) 2024 Black Sesame Technologies
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef _DAL_SUBSCRIBER_H_
#define _DAL_SUBSCRIBER_H_

#ifdef __cplusplus
extern "C" {
#endif

#include "dal/ret_type.h"
#include "dal/base_type.h"
#include "dal/sample_info.h"
#include "dal/status.h"
#include "dal/instance_handle.h"
#include "dal/string_sequence.h"
#include "dal/topic.h"
#include "dal/guid.h"
#include "dal/dds_entity.h"

// User must init callbacks' memory to 0 before using.
typedef struct dal_subscriber_listener_callbacks_s
{
    void (*on_data_on_readers)(dal_subscriber_t*, void*);
    void (*on_requested_deadline_missed)(dal_datareader_t*,
                                         dal_requested_deadline_missed_status_t*,
                                         void*);
    void (*on_requested_incompatible_qos)(dal_datareader_t*,
                                          dal_requested_incompatible_qos_status_t*,
                                          void*);
    void (*on_sample_rejected)(dal_datareader_t*, dal_sample_rejected_status_t*, void*);
    void (*on_liveliness_changed)(dal_datareader_t*, dal_liveliness_changed_status_t*, void*);
    void (*on_data_available)(dal_datareader_t*, void*);
    void (*on_subscription_matched)(dal_datareader_t*, dal_subscription_matched_status_t*, void*);
    void (*on_sample_lost)(dal_datareader_t*, dal_sample_lost_status_t*, void*);

    // offer callbacks the ability to access external resources, like binding
    // parameters;
    void* data_;
} dal_subscriber_listener_callbacks_t;

// User must init callbacks' memory to 0 before using.
typedef struct dal_datareader_listener_callbacks_s
{
    void (*on_requested_deadline_missed)(dal_datareader_t*,
                                         dal_requested_deadline_missed_status_t*,
                                         void*);
    void (*on_requested_incompatible_qos)(dal_datareader_t*,
                                          dal_requested_incompatible_qos_status_t*,
                                          void*);
    void (*on_sample_rejected)(dal_datareader_t*, dal_sample_rejected_status_t*, void*);
    void (*on_liveliness_changed)(dal_datareader_t*, dal_liveliness_changed_status_t*, void*);
    void (*on_data_available)(dal_datareader_t*, void*);
    void (*on_subscription_matched)(dal_datareader_t*, dal_subscription_matched_status_t*, void*);
    void (*on_sample_lost)(dal_datareader_t*, dal_sample_lost_status_t*, void*);

    // offer callbacks the ability to access external resources, like binding
    // parameters;
    void* data_;
} dal_datareader_listener_callbacks_t;

typedef struct dal_datareader_listener_s
{
    void* handle_;
} dal_datareader_listener_t;

dal_subscriber_listener_t*
dal_create_subscriber_listener(dal_subscriber_listener_callbacks_t callbacks);
dal_ret_t dal_delete_subscriber_listener(dal_subscriber_listener_t* listener);

dal_datareader_listener_t*
dal_create_datareader_listener(dal_datareader_listener_callbacks_t callbacks);
dal_ret_t dal_delete_datareader_listener(dal_datareader_listener_t* listener);

dal_ret_t dal_subscriber_enable(dal_subscriber_t* sub);
dal_status_condition dal_subscriber_get_statuscondition(dal_subscriber_t* sub);
dal_status_mask_t dal_subscriber_get_status_changes(dal_subscriber_t* sub);
dal_instance_handle_t dal_subscriber_get_instance_handle(dal_subscriber_t* sub);

dal_datareader_t* dal_subscriber_create_datareader(dal_subscriber_t* sub,
                                                   dal_topic_description_t* topic,
                                                   dal_datareader_qos_t* qos,
                                                   dal_datareader_listener_t* listener,
                                                   dal_status_mask_t mask);
dal_datareader_t* dal_subscriber_create_datareader_with_profile(dal_subscriber_t* sub,
                                                                dal_topic_description_t* topic,
                                                                dal_datareader_qos_t* qos,
                                                                const char* profile_name,
                                                                dal_datareader_listener_t* listener,
                                                                dal_status_mask_t mask);
dal_ret_t dal_subscriber_delete_datareader(dal_subscriber_t* sub, dal_datareader_t* datareader);
dal_ret_t dal_subscriber_delete_contained_entities(dal_subscriber_t* sub);
dal_datareader_t* dal_subscriber_lookup_datareader(dal_subscriber_t* sub,
                                                   const char* topic_name);  // TODO:
dal_ret_t dal_subscriber_get_datareaders(dal_subscriber_t* sub,
                                         DataReaderSeq* readers,
                                         dal_sample_state_mask_t sample_states,
                                         dal_view_state_mask_t view_states,
                                         dal_instance_mask_t instance_states);
dal_ret_t dal_subscriber_notify_datareaders(dal_subscriber_t* sub);
dal_ret_t dal_subscriber_set_qos(dal_subscriber_t* sub, dal_subscriber_qos_t* qos);
dal_ret_t dal_subscriber_get_qos(dal_subscriber_t* sub, dal_subscriber_qos_t* qos);
dal_ret_t dal_subscriber_set_listener(dal_subscriber_t* sub,
                                      dal_subscriber_listener_t* listener,
                                      dal_status_mask_t mask);
dal_subscriber_listener_t* dal_subscriber_get_listener(dal_subscriber_t* sub);
dal_ret_t dal_subscriber_begin_access(dal_subscriber_t* sub);
dal_ret_t dal_subscriber_end_access(dal_subscriber_t* sub);
dal_domain_participant_t* dal_subscriber_get_participant(dal_subscriber_t* sub);
dal_ret_t dal_subscriber_set_default_datareader_qos(dal_subscriber_t* sub,
                                                    dal_datareader_qos_t* qos);
dal_ret_t dal_subscriber_get_default_datareader_qos(dal_subscriber_t* sub,
                                                    dal_datareader_qos_t* qos);
dal_ret_t dal_subscriber_copy_from_topic_qos(dal_subscriber_t* sub,
                                             dal_datareader_qos_t* datareader_qos,
                                             dal_topic_qos_t* topic_qos);

dal_ret_t dal_datareader_enable(dal_datareader_t* reader);
dal_status_condition dal_datareader_get_statuscondition(dal_datareader_t* reader);
dal_status_mask_t dal_datareader_get_status_changes(dal_datareader_t* reader);
dal_instance_handle_t dal_datareader_get_instance_handle(dal_datareader_t* reader);
dal_ret_t dal_datareader_read(dal_datareader_t* reader,
                              DataSeq* datas,
                              dal_sample_info_seq_t* sample_infos,
                              long max_samples,
                              dal_sample_state_mask_t sample_states,
                              dal_view_state_mask_t view_states,
                              dal_instance_mask_t instance_states);
dal_ret_t dal_datareader_take(dal_datareader_t* reader,
                              DataSeq datas,
                              dal_sample_info_seq_t* sample_infos,
                              long max_samples,
                              dal_sample_state_mask_t sample_states,
                              dal_view_state_mask_t view_states,
                              dal_instance_mask_t instance_states);
dal_ret_t dal_datareader_read_w_condition(dal_datareader_t* reader,
                                          DataSeq datas,
                                          dal_sample_info_seq_t* sample_infos,
                                          long max_samples,
                                          dal_readcondition* a_condition);
dal_ret_t dal_datareader_take_w_condition(dal_datareader_t* reader,
                                          DataSeq datas,
                                          dal_sample_info_seq_t* sample_infos,
                                          long max_samples,
                                          dal_readcondition* a_condition);
dal_ret_t dal_datareader_read_next_sample(dal_datareader_t* reader,
                                          dal_data data_value,
                                          dal_sample_info_t* sample_info);
dal_ret_t dal_datareader_take_next_sample(dal_datareader_t* reader,
                                          dal_data data_value,
                                          dal_sample_info_t* sample_info);
dal_ret_t dal_datareader_read_instance(dal_datareader_t* reader,
                                       DataSeq datas,
                                       dal_sample_info_seq_t* sample_infos,
                                       long max_samples,
                                       dal_instance_handle_t a_handle,
                                       dal_sample_state_mask_t sample_states,
                                       dal_view_state_mask_t view_states,
                                       dal_instance_mask_t instance_states);
dal_ret_t dal_datareader_take_instance(dal_datareader_t* reader,
                                       DataSeq datas,
                                       dal_sample_info_seq_t* sample_infos,
                                       long max_samples,
                                       dal_instance_handle_t a_handle,
                                       dal_sample_state_mask_t sample_states,
                                       dal_view_state_mask_t view_states,
                                       dal_instance_mask_t instance_states);
dal_ret_t dal_datareader_read_next_instance(dal_datareader_t* reader,
                                            DataSeq datas,
                                            dal_sample_info_seq_t* sample_infos,
                                            long max_samples,
                                            dal_instance_handle_t previous_handle,
                                            dal_sample_state_mask_t sample_states,
                                            dal_view_state_mask_t view_states,
                                            dal_instance_mask_t instance_states);
dal_ret_t dal_datareader_take_next_instance(dal_datareader_t* reader,
                                            DataSeq datas,
                                            dal_sample_info_seq_t* sample_infos,
                                            long max_samples,
                                            dal_instance_handle_t previous_handle,
                                            dal_sample_state_mask_t sample_states,
                                            dal_view_state_mask_t view_states,
                                            dal_instance_mask_t instance_states);
dal_ret_t dal_datareader_read_next_instance_w_condition(dal_datareader_t* reader,
                                                        DataSeq datas,
                                                        dal_sample_info_seq_t* sample_infos,
                                                        long max_samples,
                                                        dal_instance_handle_t previous_handle,
                                                        dal_readcondition* a_condition);
dal_ret_t dal_datareader_take_next_instance_w_condition(dal_datareader_t* reader,
                                                        DataSeq datas,
                                                        dal_sample_info_seq_t* sample_infos,
                                                        long max_samples,
                                                        dal_instance_handle_t previous_handle,
                                                        dal_readcondition* a_condition);
dal_ret_t dal_datareader_return_loan(dal_datareader_t* reader,
                                     DataSeq datas,
                                     dal_sample_info_seq_t* sample_infos);
dal_ret_t dal_datareader_get_key_value(dal_datareader_t* reader,
                                       dal_data key_holder,
                                       dal_instance_handle_t handle);
dal_instance_handle_t dal_datareader_lookup_instance(dal_datareader_t* reader,
                                                     dal_data instance_data);
dal_readcondition* dal_datareader_create_readcondition(dal_datareader_t* reader,
                                                   dal_sample_state_mask_t sample_states,
                                                   dal_view_state_mask_t view_states,
                                                   dal_instance_mask_t instance_states);
dal_querycondition* dal_datareader_create_querycondition(dal_datareader_t* reader,
                                                     dal_sample_state_mask_t sample_states,
                                                     dal_view_state_mask_t view_states,
                                                     dal_instance_mask_t instance_states,
                                                     const char* query_expression,
                                                     dal_stringseq_t* query_parameters);
dal_ret_t dal_datareader_delete_readcondition(dal_datareader_t* reader, dal_readcondition* a_condition);
dal_ret_t dal_datareader_delete_contained_entities(dal_datareader_t* reader);
dal_ret_t dal_datareader_set_qos(dal_datareader_t* reader, dal_datareader_qos_t qos);
dal_ret_t dal_datareader_get_qos(dal_datareader_t* reader, dal_datareader_qos_t qos);
dal_ret_t dal_datareader_set_listener(dal_datareader_t* reader,
                                      dal_datareader_listener_t* listener,
                                      dal_status_mask_t mask);
dal_datareader_listener_t* dal_datareader_get_listener(dal_datareader_t* reader);
dal_topic_description_t* dal_datareader_get_topicdescription(dal_datareader_t* reader);
dal_subscriber_t* dal_datareader_get_subscriber(dal_datareader_t* reader);
dal_ret_t dal_datareader_get_sample_rejected_status(dal_datareader_t* reader,
                                                    dal_sample_rejected_status_t status);
dal_ret_t dal_datareader_get_liveliness_changed_status(dal_datareader_t* reader,
                                                       dal_liveliness_changed_status_t status);
dal_ret_t
dal_datareader_get_requested_deadline_missed_status(dal_datareader_t* reader,
                                                    dal_requested_deadline_missed_status_t status);
dal_ret_t dal_datareader_get_requested_incompatible_qos_status(
    dal_datareader_t* reader, dal_requested_incompatible_qos_status_t status);
dal_ret_t dal_datareader_get_subscription_matched_status(dal_datareader_t* reader,
                                                         dal_subscription_matched_status_t status);
dal_ret_t dal_datareader_get_sample_lost_status(dal_datareader_t* reader,
                                                dal_sample_lost_status_t status);
dal_ret_t dal_datareader_wait_for_historical_data(dal_datareader_t* reader,
                                                  dal_duration_t* max_wait);
dal_ret_t dal_datareader_get_matched_publications(dal_datareader_t* reader,
                                                  InstanceHandleSeq publication_handles);
dal_ret_t dal_datareader_get_matched_publication_data(dal_datareader_t* reader,
                                                      PublicationBuiltinTopicData* publication_data,
                                                      dal_instance_handle_t publication_handle);

dal_guid_t dal_datareader_get_guid(dal_datareader_t* reader);

#ifdef __cplusplus
}
#endif

#endif  // _DAL_SUBSCRIBER_H_
